module rw_arbitrate #(
    parameter
        WR0_THRESHOLD        = 16'd256,
        WR0_THRESHOLD_BEGINE = 16'd160,
        WR1_THRESHOLD        = 16'd256,
        WR1_THRESHOLD_BEGINE = 16'd160,
        RD0_THRESHOLD        = 16'd960,
        RD1_THRESHOLD        = 16'd240
)(
    input                   clk                     ,
    input                   rst_n                   ,
    // ddr3
    input                   input_fifo_rd_en        , // 输入fifo读取使能
    input                   output_fifo_wr_en       , // 输出fifo写入使能
    input      [127:0]      rd_data                 , // ddr 读取的数据，接输出fifo
    input                   rd_done                 , // 一次写完成标志
    input                   wr_done                 , // 一次读完成标志
    output reg   [ 24:0]    begin_addr              , // ddr 读写开始地址
    output reg              rw                      , // ddr 读写标志，1读 0写
    output reg   [  1:0]    mask_switch             , // 00不遮掩 01高位有效 10低位有效
    output       [127:0]    wr_data                 , // ddr 待写数据，接输入fifo
    output reg   [ 15:0]    burst_data_len          , // 突发长度
    output reg              exc                     , // 执行标志
    // wr0
    input      [  8:0]      wr0_9bit_rd_cnt         ,
    input      [ 24:0]      wr0_begin_addr          ,
    input                   wr0_rw                  ,
    input      [  1:0]      wr0_mask_switch         ,
    input      [127:0]      wr0_wr_data             ,
    input      [ 15:0]      wr0_burst_data_len      ,
    input                   wr0_exc                 ,
    output                  wr0_input_fifo_rd_en    ,
    output reg              wr0_wr_done             ,
    input                   wr0_first_frame_wr_done ,
    // rd0
    input      [ 10:0]      rd0_11bit_rd_cnt        ,
    input      [ 24:0]      rd0_begin_addr          ,
    input                   rd0_rw                  ,
    input      [ 15:0]      rd0_burst_data_len      ,
    input                   rd0_exc                 ,
    output                  rd0_output_fifo_wr_en   ,
    output     [127:0]      rd0_rd_data             ,
    output reg              rd0_rd_done             ,
    // wr1
    input      [  8:0]      wr1_9bit_rd_cnt         ,
    input      [ 24:0]      wr1_begin_addr          ,
    input                   wr1_rw                  ,
    input      [  1:0]      wr1_mask_switch         ,
    input      [127:0]      wr1_wr_data             ,
    input      [ 15:0]      wr1_burst_data_len      ,
    input                   wr1_exc                 ,
    output                  wr1_input_fifo_rd_en    ,
    output reg              wr1_wr_done             ,
    input                   wr1_first_frame_wr_done ,
    // rd1
    input      [  8:0]      rd1_9bit_rd_cnt         ,
    input      [ 24:0]      rd1_begin_addr          ,
    input                   rd1_rw                  ,
    input      [ 15:0]      rd1_burst_data_len      ,
    input                   rd1_exc                 ,
    output                  rd1_output_fifo_wr_en   ,
    output     [127:0]      rd1_rd_data             ,
    output reg              rd1_rd_done             
);

// 参数定义
localparam
    IDLE = 5'b00001,
    RD0  = 5'b00010,
    WR0  = 5'b00100,
    RD1  = 5'b01000,
    WR1  = 5'b10000;

reg [4:0] cur_state, next_state;

//--------------------------main code---------------------
// 状态机，状态转换
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

// 状态机，状态判断
always @(*) begin
    case (cur_state)
        IDLE: begin
            if((rd0_11bit_rd_cnt < RD0_THRESHOLD) && wr0_first_frame_wr_done)
                next_state = RD0;
            else if((rd1_9bit_rd_cnt < RD1_THRESHOLD) && wr1_first_frame_wr_done)
                next_state = RD1;
            else if(wr1_9bit_rd_cnt >= WR1_THRESHOLD) // 加上wr0_first_frame_wr_done的限制会使得时序错误
                next_state = WR1;
            else if(wr0_9bit_rd_cnt >= WR0_THRESHOLD)
                next_state = WR0;
            else
                next_state = IDLE;
        end 
        RD0: next_state = rd_done ? IDLE : RD0;
        WR0: next_state = wr_done ? IDLE : WR0;
        WR1: next_state = wr_done ? IDLE : WR1;
        RD1: next_state = rd_done ? IDLE : RD1;
        default: next_state = IDLE;
    endcase
end

// 状态机，状态输出
assign wr0_input_fifo_rd_en  = (cur_state == WR0) ? input_fifo_rd_en : 1'd0;
assign wr1_input_fifo_rd_en  = (cur_state == WR1) ? input_fifo_rd_en : 1'd0;
assign rd0_output_fifo_wr_en = (cur_state == RD0) ? output_fifo_wr_en : 1'd0;
assign rd1_output_fifo_wr_en = (cur_state == RD1) ? output_fifo_wr_en : 1'd0;
assign rd0_rd_data           = (cur_state == RD0) ? rd_data : 'd0;
assign rd1_rd_data           = (cur_state == RD1) ? rd_data : 'd0;
assign wr_data               = (cur_state == WR0) ? wr0_wr_data : ((cur_state == WR1) ? wr1_wr_data : 'd0);

// 状态机输出
always @(*) begin
    if(~rst_n)begin
        begin_addr      = 'd0;
        rw              = 'd0;
        mask_switch     = 'd0;
        burst_data_len  = 'd0;
        exc             = 'd0;
        rd0_rd_done     = 'd0;
        wr0_wr_done     = 'd0;
        rd1_rd_done     = 'd0;
        wr1_wr_done     = 'd0;
    end
    else begin
        case (cur_state)
            IDLE: begin
                begin_addr      = 'd0;
                rw              = 'd0;
                mask_switch     = 'd0;
                burst_data_len  = 'd0;
                exc             = 'd0;
                rd0_rd_done     = 'd0;
                wr0_wr_done     = 'd0;
                rd1_rd_done     = 'd0;
                wr1_wr_done     = 'd0;
            end
            RD0: begin
                begin_addr      = rd0_begin_addr;
                rw              = rd0_rw;
                burst_data_len  = rd0_burst_data_len;
                exc             = rd0_exc;
                rd0_rd_done     = rd_done;
            end
            WR0: begin
                begin_addr      = wr0_begin_addr;
                rw              = wr0_rw;
                mask_switch     = wr0_mask_switch;
                burst_data_len  = wr0_burst_data_len;
                exc             = wr0_exc;
                wr0_wr_done     = wr_done;
            end
            RD1: begin
                begin_addr      = rd1_begin_addr;
                rw              = rd1_rw;
                burst_data_len  = rd1_burst_data_len;
                exc             = rd1_exc;
                rd1_rd_done     = rd_done;
            end
            WR1: begin
                begin_addr      = wr1_begin_addr;
                rw              = wr1_rw;
                mask_switch     = wr1_mask_switch;
                burst_data_len  = wr1_burst_data_len;
                exc             = wr1_exc;
                wr1_wr_done     = wr_done;
            end
        endcase
    end
end
endmodule